/**
 * @file    Mutex.h
 * @brief   Contains definition of mutex
 * 
 ****************************************************************************
 * @class   wosh::Mutex
 * @brief   Multiplatform mutex used within multi-threading, based on pthread
 *          or QT library.
 *
 *
  ****************************************************************************
* @class   wosh::MutexRW
 * @brief   Multiplatform mutex used within multi-threading, based QT library.
 *          Read locks are shared, write lock are exclusive.
 *
 *
 ****************************************************************************
 * @version 0.8.499 $Id: Mutex.h 2780 2010-07-19 01:18:43Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR MutexS;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Core_Mutex_H__
 #define __WOSH_Core_Mutex_H__

 #include <woshDefs.h>

///////////////////////////////////////////
#if defined(USE_MUTEX_PTHREAD)
# include <core/posix/pthread_mutex.h>
# define _MUTEX_ARCH	"pthread"
namespace wosh {
 typedef class Mutex_pthread Mutex;
 typedef class MutexRW_pthread MutexRW;
};
///////////////////////////////////////////
#elif defined(USE_MUTEX_WIN32)
# include <core/win32/win32_mutex.h>
# define _MUTEX_ARCH	"win32-native"
namespace wosh {
 typedef class Mutex_win32 Mutex;
 typedef class MutexRW_win32 MutexRW;
};
///////////////////////////////////////////
#else // if defined(USE_MUTEX_QT)
# include <QMutex>
# include <QReadWriteLock>
# define _MUTEX_ARCH	"qt"
class Mutex_qt
 {
	public:
		/**
		 * @brief   Empty constructor. Initialize the Mutex
		 */
		Mutex_qt() { }

		/**
		 * @brief   Empty destructor. Destroy the Mutex
		 */
		virtual ~Mutex_qt() { }

	public:
		/**
		 * @brief   Lock the Mutex (does not check if Mutex was already locked)
		 * @note    check function pthread_mutex_lock() for more info
		 * @note    check function QMutex::lock() for more info
		 */
		inline void lock() const {
			this->mux.lock();
		 }
		/**
		 * @brief   UnLock the Mutex (does not check if Mutex was locked)
		 * @note    check function pthread_mutex_unlock() for more info
		 * @note    check function QMutex::unlock() for more info
		 */
		inline void unLock() const {
			this->mux.unlock();
		 }
		/**
		 * @brief   Try locking the Mutex and return response
		 * @note    check function pthread_mutex_trylock() for more info
		 */
		inline bool tryLock() const {
			return this->mux.tryLock();
		 }

	private:
		/**
		 * @brief   Empty private copy-constructor.
		 */
		Mutex_qt( const Mutex_qt& ) { }
		/**
		 * @brief   Empty private assignement-operator.
		 */
		const Mutex_qt& operator=( const Mutex_qt& ) {
			return *this;
		 }

	protected:
		mutable QMutex mux;			/// real, hidden mutex object (from QT library)

}; // class def


class MutexRW_qt
 {
	public:
		/**
		 * @brief   Empty constructor.
		 */
		MutexRW_qt() { }
		/**
		 * @brief   Empty destructor.
		 */
		virtual ~MutexRW_qt() { }

	public:
		inline void lockForRead() const {
			this->rwLock.lockForRead();
		 }

		inline void lockForWrite() const {
			this->rwLock.lockForWrite();
		 }

		/**
		 * @brief   UnLock the Mutex (does not check if Mutex was locked)
		 * @note    check function QMutex::unlock() for more info
		 */
		inline void unLock() const {
			this->rwLock.unlock();
		 }

		inline bool tryLockForRead() const {
			return this->rwLock.tryLockForRead();
		 }

		inline bool tryLockForWrite() const {
			return this->rwLock.tryLockForWrite();
		 }

	private:
		/**
		 * @brief   Empty private copy-constructor.
		 */
		MutexRW_qt( const MutexRW_qt& ) { }
		/**
		 * @brief   Empty private assignement-operator.
		 */
		const MutexRW_qt& operator=( const MutexRW_qt& ) {
			return *this;
		 }

	protected:
		mutable QReadWriteLock rwLock;	///< real, hidden mutex object (from QT library)

}; // class def

namespace wosh {
 typedef class Mutex_qt Mutex;
 typedef class MutexRW_qt MutexRW;
}; // namespace wosh

#endif

/*
The CReadWriteLock class is a very simple class that implements the Reader/Writer pattern, used for synchronizing multiple thread access to a shared resource. By allowing either multiple reader access or single write access, this class provides a better throughput than standard synchronization mechanisms like Critical Sections.
Background

Looking for a simple solution on the net, I faced the fact that the solutions often were advanced, and not developed in the spirit of KISS (Keep It Simple S*****). Therefore, I decided to implement a simple yet functional solution.

Please note that in order to prevent reader starvation, the CReadWriteLock should only be used when reader access is far more common than writer access. The reason for this is that the implementation does not contain any thread queue or similar to secure the access order, and writer threads will always win this race.
*/


//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////// LOCKERS - PURE MULTIPLATFORM

namespace wosh {

/**
 * @class   wosh::MutexLocker
 * @brief   Multiplatform mutex locker, provided for convenience.
 *
 * @version $Id: Mutex.h 2780 2010-07-19 01:18:43Z alex $
 * @author  Alessandro Polo
 */
class MutexLocker  {
	public:
		/**
		 * @brief   Create object and locks the passed Mutex.
		 * @param lockingMutex the Mutex to be used
		 */
		inline explicit MutexLocker( const Mutex* lockingMutex ) {
			this->mutex = NULL;
			if ( lockingMutex == NULL ) return;
			this->mutex = const_cast<Mutex*>(lockingMutex);
			this->mutex->lock();
		 }
		/**
		 * @brief   Destroy current object and unlocks the Mutex.
		 */
		virtual ~MutexLocker() {
			if ( this->mutex == NULL )
				return;
			this->mutex->unLock();
		 }
	protected:
		mutable Mutex* mutex;	///< reference to Mutex object.

}; // class def
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * @class   wosh::MutexLockerRead
 * @brief   Multiplatform mutex locker, provided for convenience.
 *
 * @version $Id: Mutex.h 2780 2010-07-19 01:18:43Z alex $
 * @author  Alessandro Polo
 */
class MutexLockerRead  {
	public:
		/**
		 * @brief   Create object and locks the passed MutexRW.
		 * @param lockingMutex the MutexRW to be used
		 */
		inline explicit MutexLockerRead( const MutexRW* lockingMutex )
		 {
			this->mutex = NULL;
			if ( lockingMutex == NULL ) return;
			this->mutex = const_cast<MutexRW*>(lockingMutex);
			this->mutex->lockForRead();
		 }
		/**
		 * @brief   Destroy current object and unlocks the MutexRW.
		 */
		virtual ~MutexLockerRead() {
			if ( this->mutex == NULL )
				return;
			this->mutex->unLock();
		 }
	protected:
		mutable MutexRW* mutex;	///< reference to MutexRW object.

}; // class def
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * @class   wosh::MutexLockerWrite
 * @brief   Multiplatform mutex locker, provided for convenience.
 *
 * @version $Id: Mutex.h 2780 2010-07-19 01:18:43Z alex $
 * @author  Alessandro Polo
 */
class MutexLockerWrite  {
	public:
		/**
		 * @brief   Create object and locks the passed MutexRW.
		 * @param lockingMutex the MutexRW to be used
		 */
		inline explicit MutexLockerWrite( const MutexRW* lockingMutex ) {
			this->mutex = NULL;
			if ( lockingMutex == NULL ) return;
			this->mutex = const_cast<MutexRW*>(lockingMutex);
			this->mutex->lockForWrite();
		 }
		/**
		 * @brief   Destroy current object and unlocks the MutexRW.
		 */
		virtual ~MutexLockerWrite()  {
			if ( this->mutex == NULL )
				return;
			this->mutex->unLock();
		 }
	protected:
		mutable MutexRW* mutex;		///< reference to MutexRW object.

}; // class def
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////


}; // namespace wosh

#endif //__WOSH_Core_Mutex_H__
